package edu.cdnu.filter;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import com.alibaba.fastjson.JSON;

/**
 * 重写shrio authc 的过滤器
 * 解决 当用户使用浏览器访问未认证的页面时跳转到页面
 * 	   当用户使用ajax访问未认证的数据时返回json串
 * @author LJH
 *
 */
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

	/**
	 * 在访问controller前判断是否登录，返回json，不进行重定向。
	 * 
	 * @param request
	 * @param response
	 * @return true-继续往下执行，false-该filter过滤器已经处理，不继续执行其他过滤器
	 * @throws Exception
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		//判断是否为ajax请求
		if(isAjax(request)) {
			HttpServletResponse resp = (HttpServletResponse) response;
	        HttpServletRequest req = (HttpServletRequest)request;
	        //这里是前端
			String origin = req.getHeader("Origin");
			resp.setHeader("Access-Control-Allow-Origin", origin);
			resp.setHeader("Access-Control-Allow-Methods", " POST, GET, OPTIONS, DELETE");
			resp.setHeader("Access-Control-Max-Age", "3600");
			resp.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type,application/json");
			resp.setHeader("Access-Control-Allow-Credentials", "true");
	        
			resp.setCharacterEncoding("UTF-8");
			resp.setContentType("application/json");
			
			// 这里应该不用判断，没有登录才进来
			// 判断是否登录
			Subject subject=SecurityUtils.getSubject();
			if(subject.isAuthenticated()) {
				System.err.println("Shiro Filter Login is true!!!");
				return true;
			}
			System.err.println("Shiro Filter Login is false!!!");
			Map<String,Object> resultData = new HashMap<>();
			resultData.put("code", -1);
			resultData.put("message", "登录认证失效，请重新登录!");
			
			PrintWriter out = resp.getWriter();
			out.write(JSON.toJSONString(resultData));
		}else {
			//重定向
			response.reset();
			HttpServletResponse servletResponse=(HttpServletResponse) response;
			System.out.println("重定向");
			servletResponse.sendRedirect("./index.html");
		}
		return false;
	}
	
	/**
	 * 判断是否为ajax请求
	 * @param request
	 * @return
	 */
	private boolean isAjax(ServletRequest request) {
		String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
		String axios = ((HttpServletRequest) request).getHeader("Access-Control-Request-Headers");
		String jquery = ((HttpServletRequest) request).getContentType();		
		String origin = ((HttpServletRequest) request).getHeader("origin");
		
		if(axios != null) {
			return Boolean.TRUE;
		}
		
		if(jquery != null) {
			return Boolean.TRUE;
		}
		
		if(origin != null) {
			return Boolean.TRUE;
		}
		
		if ("XMLHttpRequest".equalsIgnoreCase(header)) {
			return Boolean.TRUE;
		}
		
		return Boolean.FALSE;
	}
	
	/**
	 * 判断是否为ajax请求，网上的判断方式为前端手动设置后后端判断
	 * 一些前端没有设置，需要根据ajax的一些特性来判断
	 * 
	 * 
	 * 测试：
	 * 1.jQuery
	 * 		$.ajax(post)  		getContentType--------application/x-www-form-urlencoded
	 * 		$.post()			getContentType--------application/x-www-form-urlencoded
	 * 		$.get()				null
	 * 
	 * 2.axios
	 * 		axios.post()		getHeader("Access-Control-Request-Headers")--------content-type
	 * 		axios(post)			getHeader("Access-Control-Request-Headers")--------content-type
	 * 		axios(get)			getHeader("Access-Control-Request-Headers")--------content-type
	 * 
	 * 
	 * 3.在index.hmtl中
	 * 		外部引入的js发送$.ajax(post)  上面两项都为空，通过判断origin头解决
	 */
}
